#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
OneDrive客户端实现
提供OneDrive的完整功能实现
"""

import os
import json
import time
import hashlib
import logging
import requests
from typing import Dict, List, Optional, Any, Union, BinaryIO
from ..base_client import BaseCloudClient
from .file_operations import FileOperations
from .upload_operations import UploadOperations


class OneDriveClient(BaseCloudClient):
    """OneDrive客户端"""
    
    def __init__(self, access_token=None, refresh_token=None, client_id=None, 
                 client_secret=None, session_file=None, logger=None):
        """初始化OneDrive客户端
        
        Args:
            access_token: 访问令牌
            refresh_token: 刷新令牌
            client_id: 应用ID
            client_secret: 应用密钥
            session_file: 会话文件路径
            logger: 日志记录器
        """
        super().__init__()
        self.access_token = access_token
        self.refresh_token = refresh_token
        self.client_id = client_id
        self.client_secret = client_secret
        self.session_file = session_file
        self.logger = logger or logging.getLogger(__name__)
        
        # 初始化会话
        self.session = requests.Session()
        self.session.headers.update({
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
            'Accept': 'application/json',
            'Content-Type': 'application/json',
        })
    
    def get_provider_name(self) -> str:
        """
        获取云盘提供商名称
        
        Returns:
            str: 提供商名称
        """
        return 'onedrive'
        
        # 登录状态
        self.is_logged_in = False
        self.expire_time = None
        
        # 初始化操作模块
        self.file_ops = FileOperations(self)
        self.upload_ops = UploadOperations(self)
        
        # API基础URL
        self.api_base = "https://graph.microsoft.com/v1.0"
        
        # 加载会话
        if session_file and os.path.exists(session_file):
            self.load_session()
    
    def login(self, username: str = None, password: str = None) -> bool:
        """登录OneDrive
        
        Args:
            username: 用户名（OneDrive使用OAuth，此参数暂时保留）
            password: 密码（OneDrive使用OAuth，此参数暂时保留）
        
        Returns:
            bool: 登录是否成功
        """
        if self.access_token:
            # 验证access_token是否有效
            if self.check_login_status():
                self.is_logged_in = True
                return True
        
        if self.refresh_token:
            # 使用refresh_token获取新的access_token
            if self._refresh_access_token():
                self.is_logged_in = True
                return True
        
        self.logger.warning("OneDrive需要通过OAuth授权获取access_token")
        return False
    
    def check_login_status(self) -> bool:
        """检查登录状态
        
        Returns:
            bool: 是否已登录
        """
        if not self.access_token:
            return False
        
        # 检查token是否过期
        if self.expire_time and time.time() > self.expire_time:
            # 尝试刷新token
            return self._refresh_access_token()
        
        try:
            url = f"{self.api_base}/me/drive"
            headers = {
                'Authorization': f'Bearer {self.access_token}'
            }
            
            response = self.session.get(url, headers=headers)
            if response.status_code == 200:
                return True
        except Exception as e:
            self.logger.error(f"检查登录状态失败: {e}")
        
        return False
    
    def logout(self) -> bool:
        """登出
        
        Returns:
            bool: 登出是否成功
        """
        self.is_logged_in = False
        self.access_token = None
        self.refresh_token = None
        self.expire_time = None
        
        # 清除会话文件
        if self.session_file and os.path.exists(self.session_file):
            try:
                os.remove(self.session_file)
            except Exception as e:
                self.logger.error(f"删除会话文件失败: {e}")
        
        return True
    
    def get_files(self, folder_id: str = None, page: int = 1, 
                 page_size: int = 100) -> Optional[List[Dict[str, Any]]]:
        """获取文件列表
        
        Args:
            folder_id: 文件夹ID，None表示根目录
            page: 页码
            page_size: 每页数量
        
        Returns:
            List[Dict[str, Any]]: 文件列表
        """
        return self.file_ops.get_files(folder_id, page, page_size)
    
    def get_file_info(self, file_id: str) -> Optional[Dict[str, Any]]:
        """获取文件信息
        
        Args:
            file_id: 文件ID
        
        Returns:
            Dict[str, Any]: 文件信息
        """
        return self.file_ops.get_file_info(file_id)
    
    def create_folder(self, name: str, parent_id: str = None) -> Optional[Dict[str, Any]]:
        """创建文件夹
        
        Args:
            name: 文件夹名称
            parent_id: 父文件夹ID，None表示根目录
        
        Returns:
            Dict[str, Any]: 创建成功返回文件夹信息，失败返回None
        """
        if not self.check_login_status():
            return None
        
        if parent_id is None:
            url = f"{self.api_base}/me/drive/root/children"
        else:
            url = f"{self.api_base}/me/drive/items/{parent_id}/children"
        
        headers = {
            'Authorization': f'Bearer {self.access_token}',
            'Content-Type': 'application/json'
        }
        data = {
            'name': name,
            'folder': {},
            '@microsoft.graph.conflictBehavior': 'fail'
        }
        
        try:
            response = self.session.post(url, headers=headers, json=data)
            if response.status_code == 201:
                result = response.json()
                self.logger.info(f"文件夹创建成功: {name}")
                return {
                    'id': result.get('id'),
                    'name': result.get('name'),
                    'type': 'folder',
                    'create_time': result.get('createdDateTime'),
                    'parent_id': result.get('parentReference', {}).get('id')
                }
            else:
                self.logger.error(f"创建文件夹失败，状态码: {response.status_code}")
        except Exception as e:
            self.logger.error(f"创建文件夹请求失败: {e}")
        
        return None
    
    def delete_folder(self, folder_id: str) -> bool:
        """删除文件夹
        
        Args:
            folder_id: 文件夹ID
        
        Returns:
            bool: 删除是否成功
        """
        return self.file_ops.delete_folder(folder_id)
    
    def rename_folder(self, folder_id: str, new_name: str) -> bool:
        """重命名文件夹
        
        Args:
            folder_id: 文件夹ID
            new_name: 新名称
        
        Returns:
            bool: 重命名是否成功
        """
        return self.file_ops.rename_folder(folder_id, new_name)
    
    def upload_file(self, file_data: Union[str, bytes, BinaryIO], filename: str, 
                   parent_id: str = None, overwrite: bool = True) -> Optional[Dict[str, Any]]:
        """上传文件
        
        Args:
            file_data: 文件数据（文件路径、字节数据或文件对象）
            filename: 文件名
            parent_id: 父文件夹ID，None表示根目录
            overwrite: 是否覆盖同名文件
        
        Returns:
            Dict[str, Any]: 上传成功返回文件信息，失败返回None
        """
        return self.upload_ops.upload_file(file_data, filename, parent_id, overwrite)
    
    def download_file(self, file_id: str, save_path: str = None) -> Union[bool, bytes, None]:
        """下载文件
        
        Args:
            file_id: 文件ID
            save_path: 保存路径，None表示返回文件内容
        
        Returns:
            Union[bool, bytes, None]: 保存到文件返回bool，返回内容返回bytes，失败返回None
        """
        return self.file_ops.download_file(file_id, save_path)
    
    def delete_file(self, file_id: str) -> bool:
        """删除文件
        
        Args:
            file_id: 文件ID
        
        Returns:
            bool: 删除是否成功
        """
        return self.file_ops.delete_file(file_id)
    
    def rename_file(self, file_id: str, new_name: str) -> bool:
        """重命名文件
        
        Args:
            file_id: 文件ID
            new_name: 新名称
        
        Returns:
            bool: 重命名是否成功
        """
        return self.file_ops.rename_file(file_id, new_name)
    
    def move_file(self, file_id: str, target_folder_id: str) -> bool:
        """移动文件
        
        Args:
            file_id: 文件ID
            target_folder_id: 目标文件夹ID
        
        Returns:
            bool: 移动是否成功
        """
        return self.file_ops.move_file(file_id, target_folder_id)
    
    def copy_file(self, file_id: str, target_folder_id: str, new_name: str = None) -> Optional[Dict[str, Any]]:
        """复制文件
        
        Args:
            file_id: 文件ID
            target_folder_id: 目标文件夹ID
            new_name: 新文件名，None表示保持原名
        
        Returns:
            Dict[str, Any]: 复制成功返回新文件信息，失败返回None
        """
        return self.file_ops.copy_file(file_id, target_folder_id, new_name)
    
    def check_fast_upload(self, filename: str, file_size: int, file_md5: str, 
                         parent_id: str = None) -> bool:
        """检查文件是否支持秒传
        
        Args:
            filename: 文件名
            file_size: 文件大小（字节）
            file_md5: 文件MD5值
            parent_id: 父文件夹ID
        
        Returns:
            bool: 是否支持秒传
        """
        return self.upload_ops.check_fast_upload(filename, file_size, file_md5, parent_id)
    
    def fast_upload(self, filename: str, file_size: int, file_md5: str, 
                   parent_id: str = None) -> Optional[Dict[str, Any]]:
        """执行秒传
        
        Args:
            filename: 文件名
            file_size: 文件大小（字节）
            file_md5: 文件MD5值
            parent_id: 父文件夹ID
        
        Returns:
            Dict[str, Any]: 秒传成功返回文件信息，失败返回None
        """
        return self.upload_ops.fast_upload(filename, file_size, file_md5, parent_id)
    
    def _refresh_access_token(self) -> bool:
        """刷新访问令牌
        
        Returns:
            bool: 刷新是否成功
        """
        if not self.refresh_token or not self.client_id or not self.client_secret:
            return False
        
        url = "https://login.microsoftonline.com/common/oauth2/v2.0/token"
        data = {
            'client_id': self.client_id,
            'client_secret': self.client_secret,
            'refresh_token': self.refresh_token,
            'grant_type': 'refresh_token'
        }
        
        try:
            response = self.session.post(url, data=data)
            if response.status_code == 200:
                result = response.json()
                self.access_token = result.get('access_token')
                if 'refresh_token' in result:
                    self.refresh_token = result.get('refresh_token')
                
                # 计算过期时间
                expires_in = result.get('expires_in', 3600)
                self.expire_time = time.time() + expires_in - 300  # 提前5分钟过期
                
                self.logger.info("访问令牌刷新成功")
                return True
            else:
                self.logger.error(f"刷新访问令牌失败，状态码: {response.status_code}")
        except Exception as e:
            self.logger.error(f"刷新访问令牌请求失败: {e}")
        
        return False
    
    def _delete_file_or_folder(self, item_id: str) -> bool:
        """删除文件或文件夹
        
        Args:
            item_id: 文件或文件夹ID
        
        Returns:
            bool: 删除是否成功
        """
        if not self.check_login_status():
            return False
        
        url = f"{self.api_base}/me/drive/items/{item_id}"
        headers = {
            'Authorization': f'Bearer {self.access_token}'
        }
        
        try:
            response = self.session.delete(url, headers=headers)
            if response.status_code == 204:
                self.logger.info(f"删除成功: {item_id}")
                return True
            else:
                self.logger.error(f"删除失败，状态码: {response.status_code}")
        except Exception as e:
            self.logger.error(f"删除请求失败: {e}")
        
        return False
    
    def _rename_file_or_folder(self, item_id: str, new_name: str) -> bool:
        """重命名文件或文件夹
        
        Args:
            item_id: 文件或文件夹ID
            new_name: 新名称
        
        Returns:
            bool: 重命名是否成功
        """
        if not self.check_login_status():
            return False
        
        url = f"{self.api_base}/me/drive/items/{item_id}"
        headers = {
            'Authorization': f'Bearer {self.access_token}',
            'Content-Type': 'application/json'
        }
        data = {
            'name': new_name
        }
        
        try:
            response = self.session.patch(url, headers=headers, json=data)
            if response.status_code == 200:
                self.logger.info(f"重命名成功: {item_id} -> {new_name}")
                return True
            else:
                self.logger.error(f"重命名失败，状态码: {response.status_code}")
        except Exception as e:
            self.logger.error(f"重命名请求失败: {e}")
        
        return False
    
    def save_session(self) -> bool:
        """保存会话信息
        
        Returns:
            bool: 保存是否成功
        """
        if not self.session_file:
            return False
        
        session_data = {
            'access_token': self.access_token,
            'refresh_token': self.refresh_token,
            'client_id': self.client_id,
            'client_secret': self.client_secret,
            'expire_time': self.expire_time,
            'is_logged_in': self.is_logged_in,
            'timestamp': int(time.time())
        }
        
        try:
            os.makedirs(os.path.dirname(self.session_file), exist_ok=True)
            with open(self.session_file, 'w', encoding='utf-8') as f:
                json.dump(session_data, f, ensure_ascii=False, indent=2)
            return True
        except Exception as e:
            self.logger.error(f"保存会话失败: {e}")
            return False
    
    def load_session(self) -> bool:
        """加载会话信息
        
        Returns:
            bool: 加载是否成功
        """
        if not self.session_file or not os.path.exists(self.session_file):
            return False
        
        try:
            with open(self.session_file, 'r', encoding='utf-8') as f:
                session_data = json.load(f)
            
            self.access_token = session_data.get('access_token')
            self.refresh_token = session_data.get('refresh_token')
            self.client_id = session_data.get('client_id')
            self.client_secret = session_data.get('client_secret')
            self.expire_time = session_data.get('expire_time')
            self.is_logged_in = session_data.get('is_logged_in', False)
            
            return True
        except Exception as e:
            self.logger.error(f"加载会话失败: {e}")
            return False